# Part of Odoo. See LICENSE file for full copyright and licensing details.

import logging

from odoo.addons.website.tests.common import HttpCaseWithWebsiteUser
from odoo.exceptions import ValidationError
from odoo.fields import Command
from odoo.tests import HttpCase, tagged

from odoo.addons.http_routing.tests.common import MockRequest
from odoo.addons.website_sale.controllers.main import WebsiteSale


_logger = logging.getLogger(__name__)

ATTACHMENT_DATA = [
    b"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAEElEQVR4nGKqf3geEAAA//8EGgIyYKYzzgAAAABJRU5ErkJggg==",
    b"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAEElEQVR4nGKqvvQEEAAA//8EBQI0GMlQsAAAAABJRU5ErkJggg==",
    b"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAEElEQVR4nGKKLakBBAAA//8ChwFQsvFlAwAAAABJRU5ErkJggg==",
    b"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAEElEQVR4nGJqkdoACAAA//8CfAFRzSyOUAAAAABJRU5ErkJggg==",
    b"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAEElEQVR4nGLSfxgICAAA//8CrAFkoLBhpQAAAABJRU5ErkJggg==",
]
ATTACHMENT_COUNT = 5


@tagged('post_install', '-at_install')
class TestProductPictureController(HttpCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.website = cls.env['website'].browse(1)
        cls.WebsiteSaleController = WebsiteSale()
        cls.product = cls.env['product.product'].create({
            'name': 'Storage Test Box',
            'standard_price': 70.0,
            'list_price': 79.0,
            'website_published': True,
        })

        cls.attachments = cls.env['ir.attachment'].create([
            {
                'datas': ATTACHMENT_DATA[i],
                'name': f'image0{i}.gif',
                'public': True
            }
            for i in range(ATTACHMENT_COUNT)])

    def _create_product_images(self):
        with MockRequest(self.product.env, website=self.website):
            self.WebsiteSaleController.add_product_media(
                [{'id': attachment.id} for attachment in self.attachments],
                'image',
                self.product.id,
                self.product.product_tmpl_id.id,
            )

    def _get_product_image_data(self):
        return [
            hasattr(image, 'video_url') and image.video_url or image.image_1920
            for image in self.product._get_images()
        ]

    def test_bulk_image_upload(self):
        # Turns attachments to product_images
        self._create_product_images()

        # Check if the media now exists on the product :
        for i, image in enumerate(self.product.product_template_image_ids):
            # Check if all names are now in the product
            self.assertIn(image.name, self.attachments.mapped('name'))
            # Check if image datas are the same
            self.assertEqual(image.image_1920, ATTACHMENT_DATA[i])
        # Check if exactly ATTACHMENT_COUNT images were saved (no dupes/misses?)
        self.assertEqual(ATTACHMENT_COUNT, len(self.product.product_template_image_ids))

    def test_image_clear(self):
        # First create some images
        self._create_product_images()
        self.assertEqual(ATTACHMENT_COUNT, len(self.product.product_template_image_ids))

        # Remove all images
        # (Exception raised if error)
        with MockRequest(self.product.env, website=self.website):
            self.WebsiteSaleController.clear_product_images(
                self.product.id,
                self.product.product_tmpl_id.id,
            )
        # According to the product, there are no variants images.
        self.assertEqual(0, len(self.product.product_template_image_ids))

    def test_extra_images_with_new_variant(self):
        # Test that adding images for a variant that is not yet created works
        product_attribute = self.env['product.attribute'].create({
            "name": "Test attribute",
            "create_variant": "dynamic",
        })
        product_attribute_values = self.env['product.attribute.value'].create([
            {
                "name" : "Test Dynamic 1",
                "attribute_id": product_attribute.id,
                "sequence": 1,
            },
            {
                "name" : "Test Dynamic 2",
                "attribute_id": product_attribute.id,
                "sequence": 2,
            }
        ])
        product_template = self.env['product.template'].create({
            "name": "test product",
            "website_published": True,
        })
        product_template_attribute_line = self.env['product.template.attribute.line'].create({
            "attribute_id": product_attribute.id,
            "product_tmpl_id": product_template.id,
            "value_ids": product_attribute_values,
        })
        self.assertEqual(0, len(product_template.product_variant_ids))
        with MockRequest(product_template.env, website=self.website):
            self.WebsiteSaleController.add_product_media(
                [{'id': self.attachments[0].id}],
                'image',
                False,
                product_template.id,
                [product_template_attribute_line.product_template_value_ids[0].id],
            )
        self.assertEqual(1, len(product_template.product_variant_ids))

    def test_resequence_image_first(self):
        self._create_product_images()
        with MockRequest(self.product.env, website=self.website):
            images = self.product._get_images()
            i1, i2, i3, i4, i5, i6 = self._get_product_image_data()
            self.WebsiteSaleController.resequence_product_image(
                images[2]._name, images[2].id, 'first',
            )
            # Trigger the reordering of product.image records based on their sequence.
            self.env['product.image'].invalidate_model()
            self.assertListEqual(self._get_product_image_data(), [i3, i1, i2, i4, i5, i6])
            self.assertEqual(self.product.image_1920, i3)

    def test_resequence_image_left(self):
        self._create_product_images()
        with MockRequest(self.product.env, website=self.website):
            images = self.product._get_images()
            i1, i2, i3, i4, i5, i6 = self._get_product_image_data()
            self.WebsiteSaleController.resequence_product_image(
                images[2]._name, images[2].id, 'left',
            )
            self.env['product.image'].invalidate_model()
            self.assertListEqual(self._get_product_image_data(), [i1, i3, i2, i4, i5, i6])

    def test_resequence_image_right(self):
        self._create_product_images()
        with MockRequest(self.product.env, website=self.website):
            images = self.product._get_images()
            i1, i2, i3, i4, i5, i6 = self._get_product_image_data()
            self.WebsiteSaleController.resequence_product_image(
                images[2]._name, images[2].id, 'right',
            )
            self.env['product.image'].invalidate_model()
            self.assertListEqual(self._get_product_image_data(), [i1, i2, i4, i3, i5, i6])

    def test_resequence_image_last(self):
        self._create_product_images()
        with MockRequest(self.product.env, website=self.website):
            images = self.product._get_images()
            i1, i2, i3, i4, i5, i6 = self._get_product_image_data()
            self.WebsiteSaleController.resequence_product_image(
                images[2]._name, images[2].id, 'last',
            )
            self.env['product.image'].invalidate_model()
            self.assertListEqual(self._get_product_image_data(), [i1, i2, i4, i5, i6, i3])

    def test_resequence_image_first_to_last(self):
        """ Moving an image from first to last position is an edge case in the code. """
        self._create_product_images()
        with MockRequest(self.product.env, website=self.website):
            images = self.product._get_images()
            i1, i2, i3, i4, i5, i6 = self._get_product_image_data()
            self.WebsiteSaleController.resequence_product_image(
                images[0]._name, images[0].id, 'last',
            )
            self.env['product.image'].invalidate_model()
            self.assertListEqual(self._get_product_image_data(), [i2, i3, i4, i5, i6, i1])
            self.assertEqual(self.product.image_1920, i2)

    def test_resequence_video_left(self):
        self._create_product_images()
        with MockRequest(self.product.env, website=self.website):
            images = self.product._get_images()
            images[2].video_url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
            i1, i2, i3, i4, i5, i6 = self._get_product_image_data()
            self.WebsiteSaleController.resequence_product_image(
                images[2]._name, images[2].id, 'left',
            )
            self.env['product.image'].invalidate_model()
            self.assertListEqual(self._get_product_image_data(), [i1, i3, i2, i4, i5, i6])

    def test_resequence_video_first(self):
        """ A video can't be resequenced to first position. """
        self._create_product_images()
        with MockRequest(self.product.env, website=self.website):
            images = self.product._get_images()
            images[2].video_url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
            i1, i2, i3, i4, i5, i6 = self._get_product_image_data()
            with self.assertRaises(ValidationError):
                self.WebsiteSaleController.resequence_product_image(
                    images[2]._name, images[2].id, 'first',
                )
            self.env['product.image'].invalidate_model()
            self.assertListEqual(self._get_product_image_data(), [i1, i2, i3, i4, i5, i6])

    def test_resequence_video_replace_first(self):
        """ A video can't replace an image that was resequenced away from first position. """
        self._create_product_images()
        with MockRequest(self.product.env, website=self.website):
            images = self.product._get_images()
            images[1].video_url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
            i1, i2, i3, i4, i5, i6 = self._get_product_image_data()
            with self.assertRaises(ValidationError):
                self.WebsiteSaleController.resequence_product_image(
                    images[0]._name, images[0].id, 'right',
                )
            self.env['product.image'].invalidate_model()
            self.assertListEqual(self._get_product_image_data(), [i1, i2, i3, i4, i5, i6])


@tagged('post_install', '-at_install')
class TestWebsiteSaleEditor(HttpCaseWithWebsiteUser):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.user_website_user.group_ids += cls.env.ref('sales_team.group_sale_manager')
        cls.user_website_user.group_ids += cls.env.ref('product.group_product_manager')

    def test_category_page_and_products_snippet(self):
        category = self.env['product.public.category'].create({
            'name': 'Test Category',
        })
        self.env['product.public.category'].create({
            'parent_id': category.id,
            'name': 'Test Category - Child',
        })
        self.env['product.template'].create({
            'name': 'Test Product',
            'website_published': True,
            'public_categ_ids': [
                Command.link(category.id)
            ]
        })
        self.env['product.template'].create({
            'name': 'Test Product Outside Category',
            'website_published': True,
        })
        self.start_tour(self.env['website'].get_client_action_url('/shop'), 'category_page_and_products_snippet_edition', login="admin")
        self.start_tour('/shop', 'category_page_and_products_snippet_use', login=None)

    def test_website_sale_restricted_editor_ui(self):
        self.env['product.template'].create({
            'name': 'Test Product',
            'website_sequence': 0,
            'website_published': True,
        })
        self.start_tour(self.env['website'].get_client_action_url('/shop'), 'website_sale_restricted_editor_ui', login="website_user")

@tagged('post_install', '-at_install')
class TestProductVideoUpload(HttpCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.website = cls.env['website'].browse(1)
        cls.WebsiteSaleController = WebsiteSale()
        cls.product = cls.env['product.product'].create({
            'name': 'Test Video Product',
            'standard_price': 100.0,
            'list_price': 120.0,
            'website_published': True,
        })
        cls.video_data = {
            'src': 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',  # A placeholder video URL
            'name': 'Test Video',
        }

    def _upload_video(self):
        with MockRequest(self.product.env, website=self.website):
            self.WebsiteSaleController.add_product_media(
                [{'src': self.video_data['src'], 'name': self.video_data['name']}],
                'video',
                self.product.id,
                self.product.product_tmpl_id.id,
            )

    def test_video_upload(self):
        # Upload a video to the product
        self._upload_video()

        # Retrieve the product's media data
        video_url = self.product.product_template_image_ids[0].video_url
        image_1920 = self.product.product_template_image_ids[0].image_1920

        # Check that the video URL and thumbnail are correctly saved
        self.assertEqual(video_url, self.video_data['src'])
        self.assertIsNotNone(image_1920)  # Ensure a thumbnail was generated

        # Verify that the video was added as part of the media
        self.assertEqual(len(self.product.product_template_image_ids), 1)

    def test_video_upload_invalid(self):
        # Try to upload invalid video data (e.g., empty src)
        with MockRequest(self.product.env, website=self.website):
            with self.assertRaises(ValidationError):
                self.WebsiteSaleController.add_product_media(
                    [{'src': '', 'name': 'Invalid Video'}],
                    'video',
                    self.product.id,
                    self.product.product_tmpl_id.id,
                )
